package eu.epfc.dnet.mastermind.controller;

import eu.epfc.dnet.mastermind.model.beans.Token;
import eu.epfc.dnet.mastermind.model.pojos.GameDataModel;
import eu.epfc.dnet.mastermind.model.pojos.Line;
import eu.epfc.dnet.mastermind.model.utils.GameDataModelLoader;
import eu.epfc.dnet.mastermind.model.utils.PropositionCorrector;
import eu.epfc.dnet.mastermind.model.utils.VictoryChecker;
import eu.epfc.dnet.mastermind.services.GameManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 *
 * @author Pierre Buvé
 */
@Controller
public class GameController {

    private GameDataModel gameDataModel;
    private GameManager gameManager;
    private Map<Integer, GameDataModel> gamesMap = new HashMap<Integer, GameDataModel>();
    private VictoryChecker victoryChecker = new VictoryChecker();

    @Autowired
    /**
     * Injection du service GameManager.
     */
    public void setGameManager(GameManager gameManager) {
        this.gameManager = gameManager;
    }

    /**
     * Methode appellée lorsque la page game.htm est appellée via une requete de
     * type POST
     *
     * @param request
     * @param model
     * @return
     */
    @RequestMapping(value = "/game", method = RequestMethod.POST)
    public ModelAndView manageGame(HttpServletRequest request, ModelMap model) {
        if (request.getSession().getAttribute("username") != null) {
            // Si le paramètre username est stocké dans la session, demande l'affichage du bouton de déconnexion.
            String decoButton = "Déconnecter " + request.getSession().getAttribute("username");
            model.addAttribute("decobutton", decoButton);
        }
        if (request.getParameter("newgame") != null) {
            // Si le paramètre newgame est fourni dans la requête, execute ce bloc.
            // Création de la partie.
            int gameId = gameManager.newGame(request.getParameter("username"));

            // Récupération de la solution dans la DB depuis le gameId
            List<Token> solution = gameManager.getSolutionForGameId(gameId);

            // Création du datamodel de la partie
            gameDataModel = new GameDataModel(gameId, solution);

            // Stockage du datamodel dans la map des parties en cours.
            // TODO : penser à les retirer quand finies
            gamesMap.put(gameId, gameDataModel);

            // Insère le gamedatamodel dans le model.
            model.addAttribute("datamodel", gameDataModel.getGameData());

        } else if (request.getParameter("validline") != null) {
            // Si le paramètre validline est fourni dans la requête, execute ce bloc.
            // Récupère le gameid concerné depuis la vue
            int gameId = Integer.parseInt(request.getParameter("gameid"));

            // Récupère dans la map des parties le datamodel concerné
            GameDataModel currentGameDataModel = gamesMap.get(gameId);

            // Récupère le numéro de ligne
            int numLine = Integer.parseInt(request.getParameter("currentline"));

            // Met à jour dans le datamodel la ligne concernée
            currentGameDataModel.setCurrentLine(numLine);

            // Récupère la durée
            int duration = Integer.parseInt(request.getParameter("duration"));

            // Met à jour dans le datamodel la durée.
            currentGameDataModel.setDuration(duration);

            // Recupère les infos de la proposition envoyée par la vue et les ajoute dans une liste
            List<Token> proposal = new ArrayList<Token>();
            proposal.add(new Token(request.getParameter("token01")));
            proposal.add(new Token(request.getParameter("token02")));
            proposal.add(new Token(request.getParameter("token03")));
            proposal.add(new Token(request.getParameter("token04")));

            // Enregistre la proposition dans la DB
            gameManager.insertNewLine(proposal, numLine, gameId);

            // Récupère la solution à partir du datamodel
            List<Token> solution = currentGameDataModel.getSolution();

            // Construit une ligne à partir de la proposition
            Line line = new Line();
            for (int i = 0; i < proposal.size(); i++) {
                line.set(i, proposal.get(i));
            }

            // Corrige la proposition en la comparant avec la solution
            PropositionCorrector propositionCorrector = new PropositionCorrector();
            propositionCorrector.correctLine(line, solution);

            // Ajoute la ligne dans le currentgamedatamodel avec le bon num de ligne
            currentGameDataModel.updateCurrentLine(line);

            String status = "";

            // Si la ligne est 1, passe le statut du game "PLAYING" et update dans la DB
            if (currentGameDataModel.getCurrentLine() >= 1) {
                status = "PLAYING";
                System.out.println("Status mis à PLAYING");
            }

            // Si 4 blanc, victoire et passe le statut de la partie à "VICTORY"
            if (victoryChecker.isVictory(line)) {
                status = "VICTORY";
                System.out.println("Status mis à VICTORY");
            } // Si la ligne est 10, et si pas de victoire, passe le statut de la partie à "DEFEAT"
            else if (currentGameDataModel.getCurrentLine() == 10) {
                status = "DEFEAT";
                System.out.println("Status mis à DEFEAT");
            }

            currentGameDataModel.setStatus(status);

            // Update du game dans la DB
            gameManager.updateGame(gameId, status, duration);

            // Passage à la ligne suivante
            if (currentGameDataModel.getStatus().equals("PLAYING")) {
                currentGameDataModel.setCurrentLine(numLine + 1);
            }

            // Update du gamedate
            currentGameDataModel.updateGameData();

            // ajout du gameDataModel au modele
            model.addAttribute("datamodel", currentGameDataModel.getGameData());
        } else if (request.getParameter("loadgame") != null) {
            // Si le paramètre loadgame est fourni dans la requête, execute ce bloc.
            int currentLine = Integer.parseInt(request.getParameter("currentline"));
            int gameId = Integer.parseInt(request.getParameter("loadgame"));

            //Va chercher dans la db les infos minimum nécessaires à initialiser le gameDataModel.
            List<Token> listSolution = gameManager.getSolutionForGameId(gameId);

            //Créer le gameDataModel qui sera utilisé
            gameDataModel = new GameDataModel(gameId, listSolution);
            gameDataModel.setDuration(gameManager.getDurationForGameId(gameId));
            gameDataModel.setCurrentLine(currentLine);
            gameDataModel.setStatus("PLAYING");

            // Utilise la classe GameDataModelLoader pour completer le gameDataModel
            GameDataModelLoader gameDataModelLoader = new GameDataModelLoader();

            gameDataModelLoader.populateDataModel(gameDataModel);
            //gameDataModelLoader.correctLines(gameDataModel);

            // met a jour les données
            gameDataModel.updateGameData();

            // stocke dans la map le datamodel
            gamesMap.put(gameId, gameDataModel);

            // enregistre le datamodel dans le model
            model.addAttribute("datamodel", gameDataModel.getGameData());

        }

        return new ModelAndView("game", "model", model);
    }
}
